pub fn learn_variables() {
  // _learn_variables_datatype();
  // _learn_loop0();
  // _learn_loop_label();
  // _learn_for_0();
  //_learn_mut0();
  _learn_option();
}

// 常量
/*
常量是绑定到一个名称的不允许改变的值.常量与不可变变量的区别:
1,不允许对常量使用mut.常量总是不可变的.
2,使用const关键字而不是let.
3,必须注明值的类型
4,可以在任何作用域中声明,包括全局作用域.
5,只能被设置为常量表达式,而不能是其他任何只能在运行时计算出的值.
*/
const DAY_IN_SECONDS: u32 = 60 * 60 * 24;

fn _learn_variables_datatype() {
  println!("{}", DAY_IN_SECONDS);
  let a = 9.8 - 1.2; // 浮点数,不能保证精确性,执行结果为:8.600000000000001
  println!("{}", a);
  let b = ('x', 2.3, "hello", (3, 2));
  println!("{}, {}", b.0, b.3 .1);
  let (_, x, _, y) = b;
  println!("{}, {}", x, y.0);
  let c: [i32; 3] = [1, 2, 3];
  let d = [5; 2];
  println!("{:?}", c);
  println!("{:?}", d);
  println!("{}, {}", c[0], c[c.len() - 1]);
  let e = String::from("hello");
  println!("{}, [{}]", e.find('e').unwrap(), " wo rld ".trim());
}

// 函数定义是一个语句, let y=6; 是一个语句. 语句不返回值
// let y=6; 中的6是一个表达式,计算结果为6,并返回值6;
// 函数调用,宏调用,用大括号创建的一个新的块作用域都是一个表达式
// 在表达式的结尾加上分号,该表达式就变成了语句.

fn _learn_loop0() {
  let mut counter = 0;
  let result = loop {
    counter += 1;
    if counter == 10 {
      break counter * 2;
    }
  };
  println!("{result}");
}

// 循环标签: 在多个循环之间消除歧义
// 如果存在嵌套循环,break和continue应用于此时最内层的循环.你可以选择在一个循环上指定一个循环标签,
// 然后将标签与break或continue一起使用,使这些关键字应用于已标记的循环而不是最内层的循环.
fn _learn_loop_label() {
  let mut count = 0;
  // 这里如果不用标签,count==2时,break只会从内层循环退出到外层循环,而不会退出整个循环
  'counting_up: loop {
    let mut remaining = 10;
    loop {
      println!("remaining={remaining}");
      if remaining == 9 {
        break;
      }
      if count == 2 {
        break 'counting_up;
      }
      remaining -= 1;
    }
    count += 1;
  }
  println!("End count={count}");
}

fn _learn_for_0() {
  for n in (1..4) {
    println!("{n}");
  }
  println!("=======");
  for n in (1..4).rev() {
    println!("{n}");
  }
  println!("ok");
}

fn _learn_mut0() {
  let mut s = String::from("hello");
  // 修改了s中的指针
  s = String::from("h");
  // 修改了s指针指向的堆上字符串的内容
  s.push_str("ol");
  println!("{s}");

  let mut a = "hello";
  a = "h";

  let mut b = [1, 2, 3];
  let c = [4, 5, 6];
  b[0] = 100;
  // c[0] = 10; // 不可变
  b = c; // 实际是做了copy,因为数组长度是固定的,元素也是可copy的
  println!("c赋值给b: {:?}, {:?}", b, c);
  // c[0] = 10; // 还是不可变
  b[0] = 10; // 可变
  println!("修改b[0],c[0]不变:{:?}, {:?}", b, c);

  let mut x = [String::from("a"), String::from("b")];
  let y = [String::from("c"), String::from("d")];
  println!("x:{:?},y:{:?}", x, y);
  x = y; // 这里复制的是数组指针,长度固定,copy后失效,即可移动
         // println!("y赋值给x:{:?}", y); // y无效了,已经没有所有权了
  println!("y赋值给x:{:?}", x);

  let mut j = [String::from("a"), String::from("b")];
  let k = [String::from("c"), String::from("d")];
  println!("j:{:?},k:{:?}", j, k);
  // can't move out of type '[String;2]', a non-copy array;
  // 移不出去,String数组不是可copy的数组.这里的元素是不可copy的
  // j[1]=k[1];
}

fn _learn_option() {
  let mut x = Some(2);
  // 从选项中取出值,在其位置留下None
  let y = x.take();
  assert_eq!(x, None);
  assert_eq!(y, Some(2));

  let mut x: Option<u32> = None;
  let y = x.take();
  assert_eq!(x, None);
  assert_eq!(y, None);
}
